#include "PointLabIO/AsciiIO.h"
#include "PointLabCore/IPointCloud.h"
#include "PointLabCore/EntityCaster.h"
#include "PointLabCore/StdStringHelper.h"
#include "PointLabCore/ClientClass.h"

namespace PointLabIO
{
	AsciiIO::AsciiIO()
	{
		Handler().IORegister(this);
	}

	AsciiIO::~AsciiIO()
	{
	}

	bool AsciiIO::importSupported() const
	{
		return true;
	}

	bool AsciiIO::exportSupported() const
	{
		return false;
	}

	PointLabIO::POINTLAB_FILE_ERROR AsciiIO::loadFile(const std::string fileName, PointLabCore::Entity*& entity, PointLabIO::Options& options)
	{
		std::ifstream ifile(fileName.c_str(), std::ios::in);

		if (!ifile.is_open() || !ifile.good())
		{
			std::cout << "[AsciiIO] : cannot not open file";

			return POINTLAB_FILE_ERROR::POINTLAB_FILE_NO_LOAD;
		}

		assert(ifile);

		PointLabCore::IPointCloud* cloud = PointLabCore::ClientClass::createPointCloudInstance();

		PointLabCore::Vector3 v;

		while (!ifile.eof())
		{
			ifile >> v[0];
			ifile >> v[1];
			ifile >> v[2];

			cloud->appendPointCoord(v);
		}

		entity = cloud;

		ifile.close();

		return POINTLAB_FILE_ERROR::POINTLAB_FILE_NO_ERROR;
	}

	PointLabIO::POINTLAB_FILE_ERROR AsciiIO::saveToFile(const std::string fileName, PointLabCore::Entity* entity, PointLabIO::Options& options)
	{
		std::ofstream out(fileName.c_str(), std::ios_base::out);

		if (!out.good())
		{
			std::cout << "[AsciiIO] : cannot write to stream" << std::endl;

			return POINTLAB_FILE_ERROR::POINTLAB_FILE_NO_SAVE;
		}

		PointLabCore::IPointCloud*cloud = PointLabCore::EntityCaster::ToPointCloud(entity);

		if (cloud == nullptr)
		{
			return POINTLAB_FILE_ERROR::POINTLAB_FILE_BAD_ENTITY_TYPE;
		}
		for (PointLabCore::Uint i = 0; i < cloud->getPointNum(); i++)
		{
			if (cloud->hasPoint())
			{
				PointLabCore::Vector3 v = cloud->getPointCoord(i);
				out << v[0] << " " << v[1] << " " << v[2];
			}
			if (cloud->hasNormal())
			{
				PointLabCore::Vector3 n = cloud->getPointNormal(i);
				out << " " << n[0] << " " << n[1] << " " << n[2];
			}
			if (cloud->hasColor())
			{
				PointLabCore::Color4 c = cloud->getPointColor(i);
				out << " " << c.r << " " << c.g << " " << c.b << " " << c.a;
			}
			out << '\n';
		}

		return POINTLAB_FILE_ERROR::POINTLAB_FILE_NO_SAVE;
	}

	std::string AsciiIO::fileFilters() const
	{
		return std::string("ASCII cloud (*.txt *.asc *.neu *.xyz *.pts *.csv)");
	}

	std::string AsciiIO::defaultExtension() const
	{
		return "asc";
	}

	bool AsciiIO::canLoadExtension(std::string upperCaseExt) const
	{
		return PointLabCore::StdStringHelper::compare(upperCaseExt, "asc", PointLabCore::CaseSensitivity::YES);
	}

	bool AsciiIO::canSave(PointLabCore::CLASS_TYPE type) const
	{
		return type == PointLabCore::CLASS_TYPE::POINT_CLOUD;
	}

	PointLabIO::AsciiIO AsciiIOInstance;

	PointLabIO::AsciiIO& AsciiIOHandler()
	{
		return AsciiIOInstance;
	}
}